#ifndef MATRIX4X4_HPP_INCLUDED
#define MATRIX4X4_HPP_INCLUDED

#include <cmath>
#include "Quaternion2D.hpp"

/**	 Cool VES Math */
namespace cvMath
{
	/** Matrix class. Optimized for 2D-space. */
	template<typename T> class Mat4x4
	{
		public:
			T mat[16];

			Mat4x4();
			Mat4x4(const Mat4x4<T> & mat);
			Mat4x4<T>& operator=	(const Mat4x4<T> &copy);
	};

	// enum for enumerating the Mat4x4.mat[16] array. (just help for stupid brains)
	enum AiBj
	{
		Xx = 0, Yx, Zx, Wx,
		Xy, Yy, Zy, Wy,
		Xz, Yz, Zz, Wz,
		Xw, Yw, Zw, Ww
	};

	// Sum by matrix
	template<typename T> Mat4x4<T>& operator+=	(Mat4x4<T> &left, const Mat4x4<T> &right);
	// Subrtact by matrix
	template<typename T> Mat4x4<T>& operator-=	(Mat4x4<T> &left, const Mat4x4<T> &right);
	// Multiply by matrix
	template<typename T> Mat4x4<T>& operator*=	(Mat4x4<T> &left, const Mat4x4<T> &right);
	// Multiply by scalar
	template<typename T> Mat4x4<T>& operator*=	(Mat4x4<T> &left, const T &right);

	// Returns identity matrix.
	template<typename T> Mat4x4<T>& identity(Mat4x4<T>& m);
	template<typename T> Mat4x4<T> identity();

	// Returns translation matrix of left from vector p. (First version reuses an existing matrix, second creates one.)
	template<typename T> Mat4x4<T>& translationXY(Mat4x4<T> &left, const Vec2<T> &p);
	template<typename T> Mat4x4<T> translationXY(const Vec2<T> &p);

	// Returns rotation matrix of 2D-Quanternion q (complex number). q must be normalized.
	template<typename T> Mat4x4<T>& rotationZ(Mat4x4<T> &left, const Quat2<T> &q);
	template<typename T> Mat4x4<T> rotationZ(const Quat2<T> &q);

	// Returns rotation matrix of scalar angle.
	template<typename T> Mat4x4<T>& rotationZ(Mat4x4<T> &left, const T &angle);
	template<typename T> Mat4x4<T> rotationZ(const T &angle);

	// Returns scaling matrix of x and y. (z defaults to 1.0) Note that this only multiples Xx and Yy in the matrix.
	template<typename T> Mat4x4<T>& scaleXY(Mat4x4<T> &m, const T &x, const T &y);
	template<typename T> Mat4x4<T> scaleXY(const T &x, const T &y);

	// Returns orthographical projection matrix (right, left, bottom, top, near, far)
	template<typename T> Mat4x4<T>& ortho(Mat4x4<T>& m, const T &left, const T &right, const T &bottom, const T &top, const T &vnear, const T &vfar);
	template<typename T> Mat4x4<T> ortho(const T &left, const T &right, const T &bottom, const T &top, const T &vnear, const T &vfar);

	// Returns orthographical projection matrix. Same as ortho(m, -width/2, width/2, -height/2, height/2, -1, 1).
	// Used for "world coordinates", (0, 0) at center of the viewport
	template<typename T> Mat4x4<T>& ortho_world2d(Mat4x4<T>& m, const T &width, const T &height);
	template<typename T> Mat4x4<T> ortho_world2d(const T &width, const T &height);

	// Returns orthographical projection matrix Same as ortho(m, 0, width, height, 0, -1, 1).
	// Used for "screen coordinates", (0, 0) at left, top of the viewport.
	template<typename T> Mat4x4<T>& ortho_screen2d(Mat4x4<T>& m, const T &width, const T &height);
	template<typename T> Mat4x4<T> ortho_screen2d(const T &width, const T &height);

	// transforms vector by the matrix
	template<typename T> Vec2<T> tranform(const Vec2<T> &p, const Mat4x4<T> &m);


/// TEMPLATE IMPLEMENTATION...
#include "../../impl/Math/Matrix4x4.inl"

typedef Mat4x4<float> Mat4x4f;
typedef Mat4x4<double> Mat4x4d;

};

#endif // MATRIX4X4_HPP_INCLUDED


